type operator = Add | Sub | Mul | Div | Pow

type expr =
    Binop of expr * operator * expr
  | Float of float
  | Intgr of int
  | SizeOf of expr * int
  | Id of string
  | Negate of expr
  | NeuronRef of string * expr list
  | ExternalRef of external_ref
  | ActRef of string * expr * (string * float) list
  | WghtRef of string * (string * float) list
(*  | Function of string * (string * float) list *)
  | Conv of expr * expr
  | Filter of expr * expr * (expr list)
  | Exp of expr
  | Sin of expr
  | Cos of expr
  | Abs of expr
(*  | End *)
  | Span of expr * expr * expr
  | ForExpr of string * expr
  | Index of expr * expr list
and external_ref =
  ExtNeuron of string * expr list * string * expr list
  | Param of int * expr list 

type synap_def = {
  s_expr    : expr;
  s_for     : expr list; (* each expr must be ForExpr *)
}
type neuro_def = {
  neuro_name : string;
  neuro_ind : expr list;
  neuro_syn  : synap_def;
}
type mod_decl = {
  modcl_type : string;
  modcl_name : string;
  modcl_dims : expr list;
}
type ext_synap_def = {
  s_dest    : external_ref; 
  s_syn     : synap_def;
}
type mod_def = {
  mod_name : string;
  mod_inputs : (string * expr list) list;
  mod_outputs : (string * expr list) list;
  mod_neurons : neuro_def list;
  mod_moddecls: mod_decl list;
  mod_synaps  : ext_synap_def list;
}
type act_def = {
  act_name : string;
  act_params : (string * float) list;
  act_local: string; (* the name of the input variable *)
  act_expr : expr;
}
type wght_def = {
  wght_name : string;
  wght_params : (string * float) list;
  wght_ind  : string list;
  wght_expr : expr;
}
type program = {
  p_mdef  : mod_def list;
  p_mdecl : mod_decl list;
  p_adef  : act_def list;
  p_wdef  : wght_def list;
  p_synap : ext_synap_def list;
  p_prag  : (string * expr) list;
  p_indim : (int * (expr list)) list;
}
